<template>
  <div class="image-upload-with-validation">
    <el-upload
      class="upload-demo"
      action=""
      :auto-upload="false"
      :show-file-list="false"
      :on-change="handleImageChange"
      :before-upload="beforeUpload"
      :accept="accept"
      :disabled="disabled"
    >
      <el-button type="primary" class="upload-btn">
        <i class="el-icon-upload"></i> {{ buttonText }}
      </el-button>
    </el-upload>

    <!-- 图片预览区域 -->
    <div class="upload-preview" v-if="imageUrl">
      <img :src="imageUrl" class="preview-img" />
      <el-button link class="remove-img" @click="removeImage">
        <i class="el-icon-delete"></i> 移除
      </el-button>
    </div>

    <!-- 验证状态显示 -->
    <div v-if="imageValidation.hasError" class="validation-error">
      <el-icon class="error-icon"><Warning /></el-icon>
      <span class="error-text">{{ imageValidation.errorMessage }}</span>
    </div>

    <div
      v-else-if="imageUrl && !imageValidation.hasError"
      class="validation-success"
    >
      <el-icon class="success-icon"><CircleCheck /></el-icon>
      <span class="success-text">图片验证通过</span>
    </div>

    <p class="upload-tip">
      <span v-if="required" class="required">*</span>
      {{ tipText }}
    </p>
  </div>
</template>

<script setup>
// eslint-disable-next-line no-undef
import { ref, computed, watch } from "vue";
import { ElMessage } from "element-plus";
import { Warning, CircleCheck } from "@element-plus/icons-vue";

// eslint-disable-next-line no-undef
const props = defineProps({
  // 图片文件对象
  modelValue: {
    type: [File, null],
    default: null,
  },
  // 图片URL
  imageUrl: {
    type: String,
    default: "",
  },
  // 是否必填
  required: {
    type: Boolean,
    default: false,
  },
  // 按钮文字
  buttonText: {
    type: String,
    default: "选择图片",
  },
  // 提示文字
  tipText: {
    type: String,
    default: "建议上传JPG、PNG格式的图片，大小不超过2MB",
  },
  // 接受的文件类型
  accept: {
    type: String,
    default: "image/*",
  },
  // 最大文件大小（MB）
  maxSize: {
    type: Number,
    default: 2,
  },
  // 允许的文件格式
  allowedFormats: {
    type: Array,
    default: () => ["image/jpeg", "image/jpg", "image/png", "image/gif"],
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
});

// eslint-disable-next-line no-undef
const emit = defineEmits([
  "update:modelValue",
  "update:imageUrl",
  "change",
  "error",
  "success",
]);

// 图片验证状态管理
const imageValidation = ref({
  hasError: false,
  errorMessage: "",
});

// 计算属性：是否可以提交
const canSubmit = computed(() => {
  // 检查是否有图片验证错误
  if (imageValidation.value.hasError) {
    return false;
  }

  // 如果必填，检查是否已上传图片
  if (props.required && !props.modelValue) {
    return false;
  }

  return true;
});

// 图片验证方法
const beforeUpload = (file) => {
  // 检查文件格式
  const isAllowedFormat = props.allowedFormats.includes(file.type);
  if (!isAllowedFormat) {
    const formatText = props.allowedFormats
      .map((f) => f.split("/")[1].toUpperCase())
      .join("、");
    const errorMsg = `上传图片只能是 ${formatText} 格式!`;
    imageValidation.value.hasError = true;
    imageValidation.value.errorMessage = errorMsg;
    ElMessage.error(errorMsg);
    return false;
  }

  // 检查文件大小
  const isLtMaxSize = file.size / 1024 / 1024 < props.maxSize;
  if (!isLtMaxSize) {
    const errorMsg = `上传图片大小不能超过 ${props.maxSize}MB!`;
    imageValidation.value.hasError = true;
    imageValidation.value.errorMessage = errorMsg;
    ElMessage.error(errorMsg);
    return false;
  }

  // 验证通过，清除错误状态
  imageValidation.value.hasError = false;
  imageValidation.value.errorMessage = "";
  return true;
};

// 图片选择变化处理
const handleImageChange = (file) => {
  if (!file || !file.raw) return;

  // 先进行验证
  const isValid = beforeUpload(file.raw);

  if (isValid) {
    // 验证通过，更新文件
    emit("update:modelValue", file.raw);
    emit("update:imageUrl", URL.createObjectURL(file.raw));
    emit("change", file.raw);
    emit("success", file.raw);
  } else {
    // 验证失败，不更新文件，保持验证错误状态
    emit("update:modelValue", null);
    emit("update:imageUrl", "");
    emit("change", null);
  }
};

// 移除图片
const removeImage = () => {
  emit("update:modelValue", null);
  emit("update:imageUrl", "");
  emit("change", null);

  // 清除验证状态
  imageValidation.value.hasError = false;
  imageValidation.value.errorMessage = "";
};

// 监听外部图片URL变化
watch(
  () => props.imageUrl,
  (newUrl) => {
    if (!newUrl) {
      // 如果外部清空了图片URL，清除验证状态
      imageValidation.value.hasError = false;
      imageValidation.value.errorMessage = "";
    }
  }
);

// 监听外部文件变化
watch(
  () => props.modelValue,
  (newFile) => {
    if (!newFile) {
      // 如果外部清空了文件，清除验证状态
      imageValidation.value.hasError = false;
      imageValidation.value.errorMessage = "";
    }
  }
);

// 暴露验证状态给父组件
// eslint-disable-next-line no-undef
defineExpose({
  hasError: () => imageValidation.value.hasError,
  canSubmit: () => canSubmit.value,
  getValidationState: () => imageValidation.value,
});
</script>

<style scoped>
.image-upload-with-validation {
  width: 100%;
}

.upload-btn {
  background-color: #3498db;
  border-color: #3498db;
  transition: all 0.3s;
}

.upload-btn:hover {
  background-color: #2980b9;
  border-color: #2980b9;
}

.upload-preview {
  display: flex;
  align-items: center;
  gap: 15px;
  margin: 15px 0;
  padding: 15px;
  background: #f8fafc;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
}

.preview-img {
  max-width: 200px;
  max-height: 120px;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  padding: 4px;
  border: 1px solid #f1f5f9;
}

.remove-img {
  color: #e74c3c;
  padding: 5px 10px;
  height: auto;
}

.remove-img:hover {
  color: #c0392b;
  background-color: rgba(231, 76, 60, 0.05);
}

/* 验证状态样式 */
.validation-error,
.validation-success {
  display: flex;
  align-items: center;
  margin: 8px 0;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 14px;
}

.validation-error {
  background: #fef0f0;
  border: 1px solid #fbc4c4;
  color: #f56c6c;
}

.validation-success {
  background: #f0f9ff;
  border: 1px solid #b3d8ff;
  color: #409eff;
}

.error-icon,
.success-icon {
  margin-right: 8px;
  font-size: 16px;
}

.upload-tip {
  font-size: 12px;
  color: #95a5a6;
  margin: 5px 0 0 0;
  line-height: 1.5;
}

.required {
  color: #e74c3c;
  font-weight: bold;
}
</style>
